package apibasej.xml;

import java.util.ArrayList;
import java.util.HashMap;

import javax.xml.transform.TransformerException;

import org.w3c.dom.Attr;
import org.w3c.dom.CDATASection;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
/**
 * http://code.google.com/p/apibasej/
 * 
 * @author Julio Azevedo Lessa - apibasej@gmail.com
 * 
 */
public class ElemXML {

	private Node node;
	private DocXML doc;

	public ElemXML(Node n, DocXML docPai) {
		node = n;
		this.doc = docPai;
	}
	public Node getNode() {
		return node;
	}
	
	public ElemXML clone(){
		return new ElemXML(node.cloneNode(true),doc);
	}
	public ElemXML clone(boolean cloneChilds){
		return new ElemXML(node.cloneNode(cloneChilds),doc);
	}
	
	public DocXML getDoc() {
		return doc;
	}
	
	public void setAttribute(String name, String value){
		NamedNodeMap map = node.getAttributes();
		Node atrExistente = map.getNamedItem(name);
		if(atrExistente!=null){
			atrExistente.setNodeValue(value);
		}else{
			Attr atr = doc.getDoc().createAttribute(name);
			atr.setNodeValue(value);
			map.setNamedItem(atr);
		}
	}
	public String getAttribute(String name, boolean findIgnoreCase){
		NamedNodeMap map = node.getAttributes();
		for (int j=0; j<map.getLength(); j++){
			String nAtrib = map.item(j).getNodeName();
			if ( (findIgnoreCase?nAtrib.equalsIgnoreCase(name):nAtrib.equals(name)) ){
				return map.item(j).getNodeValue();
			}
		}
		return null;
	}
	public boolean hasSomeAttribute(){
		return node.getAttributes().getLength()>0;
	}
	
	// ADICIONA ELEMENTO FILHO. NOMETAG>NOME , TEXTOTAG>VALOR , ESTE ELEMNTO FILHO TEM IDEIA DE ATRIBUTO
	public void setAttributeElem(String name, String value, boolean useCdata, boolean findIgnCase) {
		// REMOVE ATRIBUTO SE EXISTIR
		NamedNodeMap map = node.getAttributes();
		if(map!=null){
			Node atrExistente = map.getNamedItem(name);
			if(atrExistente!=null) map.removeNamedItem(name);
		}
		ElemXML elAtrib = getFirstElemByTagName(name, false, findIgnCase);
		if(elAtrib==null){
			elAtrib = createChild(name);
		}
		if(useCdata && value!=null) elAtrib.setTextCdata(value); // se o value for null e CDATA da pau no formatador ...
		else elAtrib.setText(value);
	}
	public String getAttributeElem(String name, boolean findIgnCase) {
		ElemXML el = getFirstElemByTagName(name, false, findIgnCase);
		if(el==null) return null;
		else return el.getText(false);
	}
	
	

	public HashMap<String,String> getMapAttributes(){
		HashMap<String,String> atribs = new HashMap<String, String>();
		NamedNodeMap map = node.getAttributes();
		for (int j=0; j<map.getLength(); j++){
			atribs.put( map.item(j).getNodeName(), map.item(j).getNodeValue() );
		}
		return atribs;
	}
	
	public int getAttributesCount(){
		return node.getAttributes().getLength();
	}

	public int getChildsCount(){ //Node n
		int ct = 0;
		NodeList filhos = node.getChildNodes();
		int qtd = filhos.getLength();
		for (int i=0; i<qtd; i++){
			if(filhos.item(i).getNodeType()==Node.ELEMENT_NODE){
				ct++;
			}
		}
		return ct;
	}

	public ElemXML getChildElemByAtrib(String nameAtrib, String valueAtrib, boolean findIgnoreCase){
		ElemXML el = null;
		NodeList filhos = node.getChildNodes();
		int qtd = filhos.getLength();
		for (int i=0; i<qtd; i++){
			Node n = filhos.item(i);
			NamedNodeMap map = n.getAttributes();
			if (map!=null){
				Node na = null;
				for (int j=0; j<map.getLength(); j++){
					String nAtrib = map.item(j).getNodeName();
					if ( (findIgnoreCase?nAtrib.equalsIgnoreCase(nameAtrib):nAtrib.equals(nameAtrib)) ){
						na = map.item(j);
						break;
					}
				}
				if (na==null) return null;
				String  val = na.getNodeValue();
				if (valueAtrib!=null && (findIgnoreCase?valueAtrib.equals(val):valueAtrib.equals(val)) ){
					return new ElemXML( n,this.getDoc() );
				}
			}
		}
		return el;
	}

	public ElemXML getFirstElemByText(String nameElem, String text, boolean createIfNotExists, boolean createUpperCase, boolean findIgnoreCase){
		if (text==null) text = "";
		NodeList filhos = node.getChildNodes();
		int qtd = filhos.getLength();
		for (int i=0; i<qtd; i++){
			Node n = filhos.item(i);
			if (n.getNodeType()==Node.ELEMENT_NODE && (findIgnoreCase?n.getNodeName().equalsIgnoreCase(nameElem):n.getNodeName().equals(nameElem))
				&& (findIgnoreCase?n.getTextContent().trim().equalsIgnoreCase(text.trim()):n.getTextContent().trim().equals(text.trim()))
					){
				return new ElemXML(n,this.getDoc());
			}
		}
		ElemXML el = null;
		if (createIfNotExists){
			Element el1 = this.getDoc().getDoc().createElement( createUpperCase?nameElem.toUpperCase():nameElem );
			el1.setTextContent(text);
			node.appendChild(el1);
			el = new ElemXML(el1,this.getDoc());
		}
		return el;
	}

	public ElemXML createChild(String tagName){
		Element el1 = this.getDoc().getDoc().createElement( tagName );
		this.getNode().appendChild(el1);
		return new ElemXML(el1,this.getDoc());
	}
	
	public CDATASection setTextCdata(String text){
		if(text!=null){
			CDATASection c = this.getDoc().getDoc().createCDATASection(text);
			this.getNode().appendChild(c);
			return c;
		}else{
			setText(text);
			return null;
		}
	}	

	public ElemXML getFirstElemByChildText(String nameElem, String nameElemChild, String chidText, boolean createIfNotExists, boolean findIgnoreCase){
		if (chidText==null) chidText = "";
		NodeList filhos = node.getChildNodes();
		int qtd = filhos.getLength();
		for (int i=0; i<qtd; i++){
			Node n = filhos.item(i);
			if (n.getNodeType()==Node.ELEMENT_NODE && (findIgnoreCase?n.getNodeName().equalsIgnoreCase(nameElem):n.getNodeName().equals(nameElem)) ){
				NodeList f2 = n.getChildNodes();
				int qtd2 = f2.getLength();
				for (int j=0; j<qtd2; j++){
					Node n2 = f2.item(j);
					if (n2.getNodeType()==Node.ELEMENT_NODE
							&& ( findIgnoreCase?n2.getNodeName().equalsIgnoreCase(nameElemChild):n2.getNodeName().equals(nameElemChild) )
							&& ( findIgnoreCase?n2.getTextContent().trim().equalsIgnoreCase(chidText.trim()):n2.getTextContent().trim().equals(chidText.trim()) )
									){
						return new ElemXML(n,this.getDoc());
					}
				}
			}
		}
		ElemXML el = null;
		if (createIfNotExists){
			Element el1 = this.getDoc().getDoc().createElement( nameElem );
			Element el2 = this.getDoc().getDoc().createElement( nameElemChild );
			el2.setTextContent(chidText);
			el1.appendChild(el2);
			node.appendChild(el1);
			el = new ElemXML(el1,this.getDoc());
		}
		return el;
	}

	public void removeChild(ElemXML filho){
		this.node.removeChild(filho.getNode());
	}
	// remove a propria tag do pai
	public void removerThis(){
		Node p = this.node.getParentNode();
		if(p!=null) p.removeChild(this.node);
	}
	
	public boolean isRoot(){
		return node.getParentNode() instanceof Document;
	}
	
	public void removeAllChilds(){
		NodeList filhos = this.node.getChildNodes();
		int qtd = filhos.getLength();
		for (int i=qtd-1; i>=0; i--){
			this.node.removeChild( filhos.item(i) );
		}		
	}	

	
	public String getText(boolean permitReturnEmpty){
		//if ( returnEmptyIfNull && node.getTextContent()==null) return "";
		String t = node.getTextContent(); //retorna vazio se não tiver nada, parece que não reorna null ...
		if(!permitReturnEmpty && t!=null && t.length()==0) return null;
		return t;
	}

	public void setText(String t){
		node.setTextContent(t);
	}

	public String getNodeName(){
		return node.getNodeName();
	}

	public ElemXML getFirstElemByTagName(String nomeTag, boolean criaSeNaoExiste, boolean buscaIgnoreCase) {
		NodeList filhos = node.getChildNodes();
		int qtd = filhos.getLength();
		for (int i=0; i<qtd; i++){
			Node n = filhos.item(i);
			String nome = n.getNodeName();
			if ( (buscaIgnoreCase?nome.equalsIgnoreCase(nomeTag):nome.equals(nomeTag)) ){
				return new ElemXML(n,this.getDoc());
			}
		}
		ElemXML el = null;
		if (criaSeNaoExiste){
			Element el1 = this.getDoc().getDoc().createElement( nomeTag );
			node.appendChild(el1);
			el = new ElemXML(el1,this.getDoc());
		}
		return el;
	}

	public ArrayList<ElemXML> getElementsByTagName(String nameTag, boolean findIgnoreCase){
		ArrayList<ElemXML> elems = new ArrayList<ElemXML>();
		NodeList filhos = node.getChildNodes();
		int qtd = filhos.getLength();
		if (qtd>0){
			elems = new ArrayList<ElemXML>();
			for (int i=0; i<qtd; i++){
				Node n = filhos.item(i);
				String nome = n.getNodeName();
				if (n.getNodeType()==Node.ELEMENT_NODE && (findIgnoreCase?nome.equalsIgnoreCase(nameTag):nome.equals(nameTag)) ){
					elems.add( new ElemXML(n,this.getDoc()) );
				}
			}
		}
		return elems;
	}
	
	public String getStringXML() throws TransformerException{
		return doc.getStringXML(node);
	}

}








/* RETORNA UM MAP DE NOMETAG>TEXTOTAG COM OS FILHOS QUE TEM TEXTO E NÃO TEM ELEMS FILHOS E NÃO SE REPETEM
public HashMap<String,String> getMapElemsAtributos(){
	HashMap<String,String> atrFilhos = new HashMap<String, String>();
	NodeList filhos = node.getChildNodes();
	int qtd = filhos.getLength();
	for (int i=0; i<qtd; i++){
		Node n = filhos.item(i);
		if (n.getNodeType()==Node.ELEMENT_NODE 
				&& n.getTextContent()!=null //SE TIVER TEXTO
				&& this.getElementosByTagName(n.getNodeName(),false).size()==1 // SE TIVER SOMENTE UM FILHO COM ESTE VALOR, PARA NÃO CONFUNDIR COM OUTRS TAGS
				&& getQtdElemsFilhos(n)==0 //SE TIVER ELEMS FILHOS NÃO É TAG ATRIBUTO
				){

			atrFilhos.put(n.getNodeName(), n.getTextContent());
		}
	}
	return atrFilhos;
}*/
// ##### FIM ELEMS COMO ATRIBUTOS ##################################################
